﻿// MIT License
// 开源地址：https://gitee.com/co1024/AbcMvc
// Copyright (c) 2021-2023 1024
// Abc.Mvc=Furion+EF+SqlSugar+Pear layui admin.

using Furion.DataEncryption;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Authorization;

namespace Abc.Application.ApiAdminServices;

[ApiDescriptionSettings("ApiAdmin", Name = "ApiAccount")]
[MaApi(controller: "ApiAccount", controllerDescription: "账号登入/登出", PCode = "API")]
[IgnoreAntiforgeryToken]
public class ApiAccountService : IDynamicApiController
{
    private readonly ILogger<ApiAccountService> _logger;
    private readonly ISqlSugarClient _db;
    private readonly ISysCacheService _sysCacheService;

    public ApiAccountService(ILogger<ApiAccountService> logger
     , ISysCacheService sysCacheService
     , ISqlSugarClient db)
    {
        _logger = logger;
        _sysCacheService = sysCacheService;
        _db = db;
    }

    /// <summary>
    /// 管理登陆(WebAPI 专用，使用的JWT方式授权验证)
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [MaPermission(name: "管理登陆", actions: "Login")]
    [AllowAnonymous]
    public async Task<ApiLoginOut> Login(ApiLoginInput input)
    {
        ////验证码
        //if (!CaptchaHelper.VerifyCode(input.VerifyCode, verifyKey: "ApiAdmin"))
        //{
        //    throw Oops.Oh("验证码不正确!");
        //}
        //验证是否允许登陆（账号登陆失败次数过多）
        if (!input.Account.IsAllowLogin("AbcApi", out string errorMsg))
        {
            throw Oops.Oh(errorMsg);
        }

        var pwd = input.PassWord.ToPBKDF2();
        var dbmodel = await _db.Queryable<SysUser>()
//.FirstOrDefaultAsync(o => (o.UserType == UserType.系统维护 || o.UserType == UserType.超级管理员 || o.UserType == UserType.管理员) && o.Account == input.Account);
.FirstAsync(o => o.Account == input.Account);
        if (dbmodel == null)
        {
            throw Oops.Bah("账号或密码错误");
        }

        #region 解密提交的密码

        var appinfo = AppEx.GetConfig<AppInfoOptions>();
        var LoginPriveKey = appinfo.HtAdminLoginRsaPrivate.RsaKeyFilter();
        var LoginPublicKey = appinfo.HtAdminLoginRsaPublic.RsaKeyFilter();
        LoginRsa rsa = new LoginRsa(LoginPriveKey, LoginPublicKey);
        //解密前端提交的密钥

        var a = rsa.Encrypt(input.PassWord);

        var pwdtxt = rsa.Decrypt(input.PassWord);

        #endregion 解密提交的密码

        if (dbmodel == null)
        {
            //记录账号登陆失败
            input.Account.LoginFail("AbcApi");
            throw Oops.Bah($"账号或密码错误");
        }
        if (!pwdtxt.ToPBKDF2Compare2(dbmodel.Pwd))
        {
            //记录账号登陆失败
            input.Account.LoginFail("AbcApi");
            throw Oops.Bah($"账号或密码错误");
        }

        if (dbmodel.IsEnable == false)
        {//记录账号登陆失败
            input.Account.LoginFail("AbcApi");
            throw Oops.Bah($"账号或密码错误");
        }
        dbmodel.LastLoginTime = DateTimeOffset.Now;

        #region 日志

        //var ip = _httpContextAccessor?.HttpContext?.GetLocalIpAddressToIPv4();
        //var newlog = new WebLog()
        //{
        //    CreationTime = DateTimeOffset.Now,
        //    RemoteAddr = ip,
        //    RequestUrl = _httpContextAccessor?.HttpContext?.Request?.Path,
        //    Par1 = _httpContextAccessor?.HttpContext?.Request?.Headers["User-Agent"].ToString(),
        //    Type = "管理员登录",
        //    LogContent = $"登陆账号：{dbmodel.Account} 登陆账号ID：{dbmodel.Id} IP:{_httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString()}"

        //};

        //_userRepository.Change<WebLog>().Insert(newlog);

        #endregion 日志

        #region 设置登陆权限

        // token
        var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>()
            {
                { ClaimConst.Claim_UserId, dbmodel.Id.ToString()},  // 存储Id
                { ClaimConst.Claim_Account,dbmodel.Account?.ToString() ?? "" }, // 存储用户名
                { ClaimConst.Claim_Name,dbmodel.Nick?.ToString() ?? "" }, // 存储用户名
            });

        // 获取刷新 token
        var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, 43200); // 第二个参数是刷新 token 的有效期（分钟），默认三十天

        // 设置响应报文头
        App.HttpContext.Response.Headers["access-token"] = accessToken;
        App.HttpContext.Response.Headers["x-access-token"] = refreshToken;

        #endregion 设置登陆权限

        //设置登陆缓存
        await _sysCacheService.SetLoginAdminUserCache(dbmodel.Id);

        //账号登陆成功，移除登陆失败缓存数据
        input.Account.LoginSuccess("AbcApi");

        return dbmodel.Adapt<ApiLoginOut>(); ;
    }


    /// <summary>
    /// 获取当前登陆用户
    /// </summary>
    /// <returns></returns>
    [MaPermission(name: "获取当前登陆用户", actions: "GetLoginUser")]
    public async Task<ApiUserOut> GetLoginUser()
    {
        var user = await _sysCacheService.GetLoginAdminUser();
        return user.Adapt<ApiUserOut>();
    }

    /// <summary>
    /// 获取后台首页左侧菜单列表
    /// </summary>
    /// <param name="area">区域</param>
    /// <returns></returns>
    [MaPermission(name: "获取后台首页左侧菜单列表", actions: "GetMenus")]
    public async Task<List<PearMenuItemOut>> GetMenus(string area)
    {
        var entities = await _sysCacheService.GetMenus(area);
        var dbmenus = entities.Where(o => o.Area != null && o.Area.ToLower() == area.ToLower()).ToList();
        //获取当前登陆用户
        var user = await _sysCacheService.GetLoginAdminUser();
        if (user != null && user.Account.ToLower().Trim() == "developer".ToLower().Trim())
        {
            //开发账号，不受限制，方便开发测试，不然折腾
        }
        else
        {
            dbmenus = entities.Where(o => o.IsEnable && o.IsShow).ToList();
        }
        //如果是系统管理员或开发者，跳过
        if (user != null && user.Account.ToLower().Trim() != "administrator".ToLower().Trim() && user.Account.ToLower().Trim() != "developer".ToLower().Trim())
        {
            var userMenus = await _sysCacheService.GetMenusByUserId(user.Id);
            //var rolemenus = new List<SysMenu>();
            //foreach (var role in user.Roles)
            //{
            //    rolemenus.AddRange(role.Menus);
            //}
            //循环遍历，移除没有权限的菜单
            foreach (var menuitem in dbmenus.Where(o => o.MenuType == MenuType.菜单).Select(o => new { o.Id, o.Code }).ToList())
            {
                if (userMenus.All(o => o.Id != menuitem.Id))
                {
                    //未从用户角色菜单中找到
                    var menu = dbmenus.First(o => o.Id == menuitem.Id);
                    //验证是否有下级功能
                    if (userMenus.Any(o => o.PCode == menu.Code)) continue;//跳过，已有菜单权限

                    //没有下级功能，且没有菜单权限，移除
                    dbmenus.Remove(menu);
                }
            }
        }

        //var pearMenus = dbmenus.Select(o => new PearMenuInput() { MenuType = o.MenuType, MId = o.Code, PMId = o.PCode, Name = o.Name, Icon = o.Icon, Sort = o.Sort, Url = o.Url }).ToList();
        var pearMenus = dbmenus.Adapt<List<PearMenuItem>>();

        var rmenus = pearMenus.GetMenus(pid: area);
        //为了提高用户体验，系统维护人员可以看到空目录方便修改优化
        if (user != null && user.UserType != UserType.系统维护)
        {
            //遍历，移除没有下级的空目录
            foreach (var item in rmenus.ToList())
            {
                //跳过主菜单，没有上级的菜单
                if (item.type == 1) continue;
                // 如果不是“系统维护”账号developer 移除开发工具
                if (item.children == null || item.children.Count <= 0 || item.id.ToString() == "ApiAdmin_Developer")
                {
                    rmenus.Remove(item);
                }
            }
        }
        //排除后台首页菜单
        rmenus = rmenus.Where(o => o.id.ToString() != "HtAdmin_Home_Index").ToList();
        return rmenus;
    }
}